﻿using System;
using System.Collections.Generic;
using System.Text;

using Daybreak.Core.SceneGraph;
using Daybreak.Core.Terrains;
using Daybreak.Core.Mathematics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Daybreak.Core
{
    public partial class Scene
    {
        /// <summary>
        /// Embodies the entire set of information that can be visualized from the contents of a COLLADA 
        /// or any other compatible resource. 
        /// </summary>
        /// <remarks>
        /// The hierarchical structure of the visual_scene is organized into a scene graph. 
        /// A scene graph is a directed acyclic graph (DAG) or tree data structure 
        /// that contains nodes of visual information and related data
        /// </remarks>
        public class VisualScene
        {
            private AmbientLight ambientLight;
            private DirectionalLight dirLight;
            private Transform.Matrix44 dirNode;

            public string Name;

            public Scene Environment;

            /// <summary>
            /// Animation frame rate
            /// </summary>
            public float FrameRate = 30;
            /// <summary>
            /// Hierarchical relationship of elements in the scene. 
            /// </summary>
            public List<Node> RootNodes = new List<Node>();

            private List<AnimationInstance> playingAnimations = new List<AnimationInstance>(8);

            public VisualScene(string name, Scene owner)
            {
                Name = name;
                Environment = owner;
            }

            public void CreateDefaultLighting()
            {
                Light aNode = AmbientLight.Node(Color.DarkGray);
                ambientLight = aNode.LightTechnique as AmbientLight;

                dirNode = new Transform.Matrix44();
                Vector3 pos = new Vector3(1000, 1000, 0);

                pos = Astronomy.GetGeocentricPosition(DateTime.UtcNow).ToVector3();

                dirNode.Move(pos.X, pos.Y, pos.Z, false);
                dirNode.Name = "default_lighting";

                Light dNode = DirectionalLight.Node(Color.White);
                dirLight = dNode.LightTechnique as DirectionalLight;
                
                dirNode.AddChild(dNode);
                dirNode.AddChild(aNode);

                AddRootNode(dirNode);

            }

            public void AddRootNode(Node node)
            {
                RootNodes.Add(node);
            }

            public void ApplyVisitor(NodeVisitor visitor)
            {
                for (int i = 0; i < RootNodes.Count; i++)
                {
                    Node node = RootNodes[i];

                    if (node != null)
                        node.Accept(visitor);
                }
            }

            public bool PlayAnimation(AnimationClip clip, bool loop)
            {
                AnimationInstance movie = new AnimationInstance(clip.Animations, clip.End);
                movie.Loop = loop;
                playingAnimations.Add(movie);

                // TODO: check if the same animation is playing already and return false then

                return true;
            }

            public void PlayAnimationChain(params AnimationInstance[] anims)
            {
                AnimationChain chain = new AnimationChain(anims);
                chain.Loop = false;
                playingAnimations.Add(chain);
            }

            public void UpdateAnimations(float delta)
            {
                if (delta == 0)
                    return;

                for (int i = 0; i < playingAnimations.Count; i++)
                {
                    playingAnimations[i].Advance(delta);
                }
            }

            public AmbientLight AmbientLight
            {
                get { return ambientLight; }
            }

            public DirectionalLight DirectionalLight
            {
                get { return dirLight; }
            }

        }

    }
}
